package org.teremail.server;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;

import javax.servlet.ServletException;

import org.teremail.ServerSingleton;
import org.teremail.client.MailService;
import org.teremail.client.MessageSummary;
import org.teremail.common.Log;
import org.teremail.delivery.Exchange;
import org.teremail.mailbox.Folder;
import org.teremail.mailbox.FolderEntry;
import org.teremail.mailbox.FolderNotExistsException;
import org.teremail.mailbox.Mailbox;
import org.teremail.mailbox.MailboxExistsException;
import org.teremail.mailbox.MailboxNotExistsException;
import org.teremail.mailbox.Path;
import org.teremail.message.ContentEntity;
import org.teremail.message.EntityVisitor;
import org.teremail.message.EntityVisitorAdaptor;
import org.teremail.message.MessageHeaders;
import org.teremail.message.SimpleEntity;
import org.teremail.message.SimpleMessage;
import org.teremail.store.Store;
import org.teremail.util.IO;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class MailServiceImpl extends RemoteServiceServlet implements
        MailService {

    private static final long serialVersionUID = 1L;
    private static final Log log = Log.getLog(MailServiceImpl.class);
    
    private Exchange exchange = null;
    
    /**
     * @see javax.servlet.GenericServlet#init()
     */
    @Override
    public void init() throws ServletException {
        setExchange(ServerSingleton.getInstance().getExchange());
    }
    
    void setExchange(Exchange exchange) {
        this.exchange = exchange;
    }

    public String[] getFolders(String mailbox) throws Exception {
        Mailbox m;
        try {
            m = exchange.getMailboxService().getMailbox(mailbox);
        } catch (MailboxNotExistsException e) {
            try {
                m = exchange.getMailboxService().create(mailbox);
            } catch (MailboxExistsException e1) {
                throw new Exception(e1.getMessage());
            }
        }
        
        List<Folder> folders = m.getFolders(Path.ROOT);
        String[] folderNames = new String[folders.size()];
        int i = 0;
        for (Folder folder : folders) {
            folderNames[i++] = folder.getName();
        }
        return folderNames;
    }

    public MessageSummary[] getMessageSummaries(String mailbox, String folder) throws Exception {
        
        try {
            Mailbox mbox = exchange.getMailboxService().getMailbox(mailbox);
            Folder f = mbox.getFolder(Path.path(folder));
            List<FolderEntry> entries = f.getFolderEntries(0, 10, Folder.SortKey.UID);
            MessageSummary[] summaries = new MessageSummary[entries.size()];
            int i = 0;
            for (FolderEntry entry : entries) {
                int uid = entry.getUid();
                MessageHeaders headers = entry.getMessageHeaders();
                String from = headers.getFrom();
                String subject = headers.getSubject();
                String date = headers.getDate();
                summaries[i++] = new MessageSummary(uid, from, subject, date);
            }
            return summaries;
        } catch (MailboxNotExistsException e) {
            log.error(e, "Failed to load message summaries");
            throw new Exception(e.getMessage());
        } catch (FolderNotExistsException e) {
            log.error(e, "Failed to load message summaries");
            throw new Exception(e.getMessage());
        } catch (Exception e) {
            log.error(e, "Failed to load message summaries");
            throw new Exception(e.getMessage());
        }
        
    }
    
    public String getMessage(String mailbox, String folder, int uid) throws Exception {
        try {
            Mailbox mbox = exchange.getMailboxService().getMailbox(mailbox);
            Folder f = mbox.getFolder(Path.path(folder));
            
            final StringBuilder sb = new StringBuilder();
            final Store store = exchange.getStore();
            
            EntityVisitor ev = new EntityVisitorAdaptor() {
                
                private void load(ContentEntity e) {
                    String id = e.getContent().getId();
                    try {
                        String body = IO.toString(store.getInputStream(id), 
                                Charset.forName("UTF-8"));
                        sb.append(body);
                    } catch (IOException ioe) {
                        throw new RuntimeException(ioe);
                    }                    
                }
                
                @Override
                public void visitSimpleEntity(SimpleEntity simpleEntity) {
                    load(simpleEntity);
                }

                @Override
                public void visitSimpleMessage(SimpleMessage simpleMessage) {
                    load(simpleMessage);
                }
            };
            
            f.getMessage(uid).getMessage().accept(ev); 
            return sb.toString();
            
        } catch (MailboxNotExistsException e) {
            log.error(e, "Failed to load message summaries");
            throw new Exception(e.getMessage());
        } catch (FolderNotExistsException e) {
            log.error(e, "Failed to load message summaries");
            throw new Exception(e.getMessage());
        } catch (Exception e) {
            log.error(e, "Failed to load message summaries");
            throw new Exception(e.getMessage());
        }
        
    }

}
